package srt.tool;

import java.util.HashMap;
import java.util.Map;

import srt.ast.AssignStmt;
import srt.ast.Decl;
import srt.ast.DeclRef;
import srt.ast.Expr;
import srt.ast.visitor.impl.DefaultVisitor;
//Visitor implementation to make program SSA compatible
public class SSAVisitor extends DefaultVisitor {
	
	//Maps variables names to their indicators
	Map<String, Integer> variables = new HashMap<String, Integer>();

	public SSAVisitor() {
		super(true);
	}

	//Get new variable name by concatenating name + $ + indicator
	private String getName(String name) {
		if(variables.get(name) == null){
			variables.put(name, 0);
		}
		return name + "$" + variables.get(name);
	}

	//increments variable indicator if present or adds new variable with indicator 0
	private void increment(String name) {
		if(variables.get(name) != null){
			variables.put(name, variables.get(name) + 1);
		}else{
			variables.put(name, 0);
		}
	}

	//add all declared variables to the variables map
	@Override
	public Object visit(Decl decl) {

		variables.put(decl.getName(), 0);

		return new Decl(getName(decl.getName()), decl.getType(),
				decl.getNodeInfo());
	}

	//renames variables names if they are not the Predicates in declaration reference
	@Override
	public Object visit(DeclRef declRef) {

		if (declRef.getName().charAt(0) != '$') {
			return new DeclRef(getName(declRef.getName()),
					declRef.getNodeInfo());
		} else {
			return declRef;
		}
	}

	//renames variables names if they are not the Predicates in assignment statements
	@Override
	public Object visit(AssignStmt assignment) {

		if (assignment.getLhs().getName().charAt(0) != '$') {
			Expr rhs = (Expr) this.visit(assignment.getRhs());

			increment(assignment.getLhs().getName());

			DeclRef lhs = (DeclRef) this.visit(assignment.getLhs());

			return new AssignStmt(lhs, rhs);
		} else {
			Expr rhs = (Expr) this.visit(assignment.getRhs());
			return new AssignStmt(assignment.getLhs(), rhs);
		}
	}

}
